package com.app.utils.spring.interceptor;

import com.app.utils.base.http.McodeHandler;
import com.app.utils.base.http.RequestHandler;
import com.app.utils.base.http.ResponseHandler;
import com.app.utils.base.http.ResultUtil;
import com.app.utils.base.j2se.*;
import com.app.utils.redis.Redis;
import com.app.utils.redis.UserKey;
import com.app.utils.spring.ServerUrl;
import com.app.utils.spring.config.ResultCode;
import com.app.utils.spring.config.SystemError;
import com.app.utils.spring.properties.Config;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Description
 * Created by 王伟
 * Date create on 17:52 2019/11/19.
 */
public class ServerInterceptor implements HandlerInterceptor {
    private Map<String,ServerUrl> urls = new HashMap<>();

    ServerInterceptor() {
        //加载url
        Map<String,ServerUrl> urls2 = new HashMap<>();
        for(Map.Entry<String, String> entry : Config.pp.entrySet()){
            if(!entry.getKey().startsWith("/")){
                continue;
            }
            try {
                ServerUrl serverUrl = JsonUtil.jsonToBean(entry.getValue(), ServerUrl.class);
                String error = serverUrl.check();
                if(null != error){
                    throw new RuntimeException(error);
                }
                serverUrl.url = entry.getKey();
                urls2.put(entry.getKey(), serverUrl);
            } catch (Exception e) {
                Logger.error(String.format("模拟接口%s加载失败",entry.getKey()), e);
            }
        }
        urls = urls2;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取uri 设置请求编码集
        request.setCharacterEncoding("utf-8");
        request.setAttribute("duoke.system.time", System.currentTimeMillis());
        String uri = request.getRequestURI();
        String ip = RequestHandler.getIP(request);
        //限制请求内容大小
        String rpid = UUID.randomUUID().toString();//生成请求编号
        if (request.getContentLength() > 1048576) {
            String error = "请求内容大小超过限制"+(1048576/1024)+"KB";
            Logger.info("%s [server]receive:[%s] %s", rpid, uri, error);
            ResponseHandler.write(ResultUtil.error(6002, error), request, response);
            return false;
        }
        try{
            //各种认证
            ServerUrl serverUrl = auth(uri, request, response);
            //模拟接口
            if(serverUrl.ismock){
                ResponseHandler.write(Config.pp.get("mock."+serverUrl.url), request, response);
                return false;
            }
        } catch (Exception e) {
            SystemError error = SystemError.exp2Se(e);
            if(error.getRetcode() == ResultCode.SERVER_ERROR){
                Logger.error(uri, e);
            }
            ResponseHandler.write(ResultUtil.error(error.getErrorCode(), error.getMessage()), request, response);
            return false;
        }
        //注入IP
        request.setAttribute("ip", ip);
        return true;
    }

    /**
     * 各种限制
     * 签名 + referer + 请求次数
     */
    private ServerUrl auth(String uri, HttpServletRequest request, HttpServletResponse response){
        //请求认证
        ServerUrl url = urls.get(uri);
        String uid = null;
        if(null != url && url.loginAuth){
            String alias = request.getParameter("alias");
            String token = request.getParameter("token");
            uid = Redis.str.get(UserKey.uidByToken(token));
            if(Common.isEmpty(uid) || McodeHandler.from32Radix(alias)!= Convert.objToLong(uid))SystemError.wrapBs("6007", Config.pp.get("6007"));
            request.setAttribute("uid", Convert.objToLong(uid));
            return url;
        }
        //请求次数限制
        if(Common.isNotEmpty(url) && url.loginAuth && url.userLimit && url.userCount>0){
            long min = DateHandler.getLongFormatDate(System.currentTimeMillis())/100000;
            Long limit = Redis.hash.hincrBy("AuthLimit_"+min,uid+"."+uri,1L,60);
            if(null != limit && limit > url.userCount){
                SystemError.wrapBs("6009", "请1分钟后再试");
            }
        }
        //请求次数限制
        if(Common.isNotEmpty(url) && url.urlLimit && url.urlCount>0){
            long min = DateHandler.getLongFormatDate(System.currentTimeMillis())/100000;
            Long limit = Redis.hash.hincrBy("AuthLimit_"+min,uri,1L,60);
            if(null != limit && limit > url.urlCount){
                SystemError.wrapBs("6009", "请勿频繁请求");
            }
        }
        return new ServerUrl();
    }
}
